使用缓冲提高文件I/O效率

缓冲区的大小对性能有很大的影响, 原因是系统调用需要在用户-内核之间转换, 会消耗很多时间

使用缓冲的who命令

原来的who命令每次只取一个用户, 大大浪费了时间, 我们可以一次取16条记录,

首先编写 utmplib.c

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utmp.h>
#include <unistd.h>

#define NRECS 16
#define NULLUT ((struct utmp *)NULL) // 将NULL指针强制转化成 struct utmp指针
#define UTSIZE (sizeof(struct utmp))

static char utmpbuf[NRECS * UTSIZE];
static int num_recs;
static int cur_rec;
static int fd_utmp = -1;

int utmp_reload();

int utmp_open(char * filename)
{
    fd_utmp = open(filename, O_RDONLY);
    cur_rec = num_recs = 0;
    return fd_utmp;
}

struct utmp *utmp_next()
{
    struct utmp *recp;
    if (fd_utmp == -1)
        return NULLUT;

    if (cur_rec == num_recs && utmp_reload() == 0)
        return NULLUT;

    recp = (struct utmp *) &utmpbuf[cur_rec * UTSIZE];
    cur_rec++;
    return recp;
}

int utmp_reload()
{
    int amt_read;
    amt_read = read(fd_utmp, utmpbuf, NRECS * UTSIZE);
    num_recs = amt_read/UTSIZE;
    cur_rec = 0;
    return num_recs;
}

void utmp_close()
{
    if (fd_utmp != -1)
        close(fd_utmp);
}

/**
 * 变量 num_recs记录了缓冲区中的数据个数,
 * 变量 cur_rec 记录了缓冲区已被使用的数据个数
 * 每次从缓冲区中读数据前, 先检查 cur_rec 的值是否登陆 num_recs,
 * 如果相等说明缓冲区已经没有可用句库, 就调用 read 从硬盘上读数据
 * 来填满缓冲区, 在返回数据前, 增加cur_rec的值
 * 函数 utmp_next 返回指向结构的指针,
 */

然后根据utmplib.c提供的接口编写who3.c

#include <stdio.h>
#include <sys/types.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>

#define SHOWHOST

void show_info(struct utmp *);
void show_time(time_t);

int main()
{
    struct utmp *utbufp,
                *utmp_next();

    if (utmp_open(UTMP_FILE) == -1)
    {
        perror(UTMP_FILE);
        return -1;
    }

    while ((utbufp = utmp_next()) != ((struct utmp *) NULL))
        show_info(utbufp);
    utmp_close();
    return 0;
}

void show_info(struct utmp * utbufp)
{
    if (utbufp->ut_type != USER_PROCESS)
        return;

    printf("%-8.8s", utbufp->ut_user);
    printf(" ");
    printf("%-8.8s", utbufp->ut_line);
    show_time(utbufp->ut_tv.tv_sec);
#ifdef SHOWHOST
    printf("(%s)", utbufp->ut_host);
#endif
    printf("\n");
}

void show_time(long timeval)
{
    char *cp;
    cp = ctime(&timeval);
    printf("%12.12s", cp + 4);
}
utmplib.c提供了简单清晰的操作缓冲区的接口, 并隐藏了细节,who3.c可以根据utmplib.c很容易的写出使用缓冲区的who

然后编译

cc utmplib.c who3.c -o who3